

import java.util.Date;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.swift.cfg4u.instance.ConstInstance;
import org.swift.cfg4u.servlet.ConfigController;
import org.swift.util.datetime.FormatTime;
import org.swift.util.lang.IdGen;

import com.cmcc.shandong.wap.util.ShanDongSignEnc;
import com.cmcc.shandong.wap.util.SignEncException;
import com.cmcc.shandong.wap.util.XmlMessgeUtil;

import cmpay.CmpayShanDongNew2Action;
import net.caiban.utils.DateUtil;
import net.caiban.utils.http.HttpRequestUtil;

/**
 * 
 * <p>Title:ServiceApi</>
 * <p>Description:</p>
 * @author chen
 * 2017年10月19日下午3:53:45
 */
public class ServiceApi {
	private static String logPre = "山东移动掌厅WAP支付:";
	private static Logger log = Logger.getLogger(ServiceApi.class );
	private static final int TOKENARRLENGTH = 3;
	private static final String TXNTYP_WAP = "S";
//	private static final String URL = ConstInstance.getValuedByKeyd(CmpayShanDongNew2Action.CODE, "url");
//	private static final String CALLBACK_URL = ConstInstance.getValuedByKeyd(CmpayShanDongNew2Action.CODE, "callbackUrl");
//	private static final String MERID = ConstInstance.getValuedByKeyd(CmpayShanDongNew2Action.CODE, "merchantId");
//	
	private static final String URL = "http://211.137.182.167:29090/";
	private static final String CALLBACK_URL = ConstInstance.getValuedByKeyd(CmpayShanDongNew2Action.CODE, "callbackUrl");
	private static final String MERID = "888001513000001";
	
	public static void main(String[] args){
		ConfigController.start();
		String merId = "";
		String currency = "";
		String price = "1";
		Date orderLogTime = new Date();
		String goodsProductInfo = "搜狐视频15元月卡";
		long batchId = 1L;
		String mobile = "18668078971";
		String goodsProductName = goodsProductInfo;
		
		try {
		//String orderId = ServiceApi.genOrderId();
		//RespWap res = ServiceApi.wap(currency, orderId, price, orderLogTime, goodsProductInfo, goodsProductName, batchId, mobile);
		//System.out.println(res.getRespCode() + "," + res.getRespMsg() + "," + res.getToken());
		//String r = ServiceApi.dealWithToken(res.getToken());
			
		String orderId = "20171216100252361875";
		RespQueryOrder res = ServiceApi.queryOrder(orderId);
		System.out.println(res.getRespCode() + "," + res.getRespMsg() + "," + res.getOrdsts());
			
//		String requestId = FormatTime.toString(new Date(), "yyyyMMddHHmmssSSS") + IdGen.genRandNum(33);
//		RespBase res = ServiceApi.cancel(orderId, price, requestId, orderLogTime);
//		System.out.println(res.getRespCode() + "," + res.getRespMsg());
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.exit( 0 );
	}
	
	/**
	 * 
	* @描述: 生成一个微能订单号 定长20位
	* @创建人:cyb
	* @创建时间:2017年10月19日 下午3:57:36
	* @修改人：
	* @修改时间：
	* @修改描述
	* @param @return
	* @param @throws Exception
	* @return String
	* @throws
	 */
	public static String genOrderId() throws Exception {
		return FormatTime.toString(new Date(), "yyyyMMddHHmmssSSS") + IdGen.genRandNum(3);
	}
	
	/**
	 * 
	* @描述: 订单查询
	* @创建人:cyb
	* @创建时间:2017年10月19日 下午3:28:27
	* @修改人：
	* @修改时间：
	* @修改描述
	* @param @param orderId 微能订单号
	* @param @return
	* @return RespQueryOrder
	* @throws
	 */
	public static RespQueryOrder queryOrder(String orderId){
		RespQueryOrder respResult = new RespQueryOrder();
		
		StringBuilder mapToSign = new StringBuilder();
		StringBuilder request = new StringBuilder();
		request.append("<MESSAGE>");
		String mcode = "101455";
		request.append("<MCODE>").append(mcode).append("</MCODE>");
		mapToSign.append("MCODE=" + mcode);
		
		Date currDate = new Date();
		String mid = FormatTime.toString(currDate, "yyyyMMddHHmmss");
		request.append("<MID>").append(mid).append("</MID>");
		mapToSign.append("&MID=" + mid);
		
		String date = DateUtil.toString(currDate, "yyyyMMdd");
		request.append("<DATE>").append(date).append("</DATE>");
		mapToSign.append("&DATE=" + date);
		
		String time = DateUtil.toString(currDate, "HHmmss");
		request.append("<TIME>").append(time).append("</TIME>");
		mapToSign.append("&TIME=" + time);
		
		request.append("<MERID>").append(MERID).append("</MERID>");
		mapToSign.append("&MERID=" + MERID);
		
		request.append("<ORDERID>").append(orderId).append("</ORDERID>");
		mapToSign.append("&ORDERID=" + orderId);
		
		//SIGN
		String sign = "";
		try {
			sign = ShanDongSignEnc.sign(mapToSign.toString());
		} catch (Exception e) {
			log.error(logPre + "加密发生异常"+e.getMessage(),e);
			return respResult;
		}
		request.append("<SIGN>").append(sign).append("</SIGN>");
		request.append("</MESSAGE>");
		String content = request.toString();
		String res = HttpRequestUtil.httpPost(URL, content);
		try {
			Map<String,String> resMap = XmlMessgeUtil.xml2Map(res);
			String signStr = resMap.get("SIGNSTR");
			String signString = resMap.get("SIGN");
			try {
				if(!ShanDongSignEnc.verify(signStr, signString)){
					log.info(logPre + "验签失败" + res);
					return respResult;
				}
			} catch (Exception e) {
				log.error(logPre + "验签发生异常"+e.getMessage(),e);
				return respResult;
			}
			
			String rcode = resMap.get("RCODE");
			String desc = resMap.get("DESC");
			String ordsts = resMap.get("ORDSTS");
			respResult.setRespCode(rcode);
			respResult.setRespMsg(desc);
			respResult.setOrdsts(ordsts);
		} catch (Exception e) {
			log.error(logPre + "xml2Map发生异常"+e.getMessage(),e);
		}
		return respResult;
	}
	
	/**
	 * 
	* @描述: 撤销(全额撤销)或退货(支持部分退款)
	* @创建人:cyb
	* @创建时间:2017年10月16日 下午2:18:22
	* @修改人：
	* @修改时间：
	* @修改描述
	* @param @return
	* @return String
	* @throws
	 */
	public static RespBase cancel(String orderId,String price,String requestId,Date orderLogTime){
		RespBase respResult = new RespBase();
		
		StringBuilder mapToSign = new StringBuilder();
		StringBuilder request = new StringBuilder();
		request.append("<MESSAGE>");
		String mcode = "101450";
		request.append("<MCODE>").append(mcode).append("</MCODE>");
		mapToSign.append("MCODE=" + mcode);
		
		Date currDate = new Date();
		String mid = FormatTime.toString(currDate, "yyyyMMddHHmmss");
		request.append("<MID>").append(mid).append("</MID>");
		mapToSign.append("&MID=" + mid);
		
		String date = DateUtil.toString(currDate, "yyyyMMdd");
		request.append("<DATE>").append(date).append("</DATE>");
		mapToSign.append("&DATE=" + date);
		
		String time = DateUtil.toString(currDate, "HHmmss");
		request.append("<TIME>").append(time).append("</TIME>");
		mapToSign.append("&TIME=" + time);
		
		request.append("<MERID>").append(MERID).append("</MERID>");
		mapToSign.append("&MERID=" + MERID);
		
		request.append("<ORDERID>").append(orderId).append("</ORDERID>");
		mapToSign.append("&ORDERID=" + orderId);
		
		request.append("<AMOUT>").append(price).append("</AMOUT>");
		mapToSign.append("&AMOUT=" + price);
		
		//商户请求号 50位,商户请求的交易流水号，唯一 TODO 撤销退款时存在订单表的ext1中
		//String requestId = FormatTime.toString(new Date(), "yyyyMMddHHmmssSSS") + IdGen.genRandNum(33);
		request.append("<REQUESTID>").append(requestId).append("</REQUESTID>");
		mapToSign.append("&REQUESTID=" + requestId);
		
		String orderDate = DateUtil.toString(orderLogTime, "yyyyMMdd");
		request.append("<ORDERDATE>").append(orderDate).append("</ORDERDATE>");
		mapToSign.append("&ORDERDATE=" + orderDate);
		
		//CNYTYP 退款金额类型 901:可提现金额 902:不可提现金额 一般固定901
		String cnyTyp = "901";
		request.append("<CNYTYP>").append(cnyTyp).append("</CNYTYP>");
		mapToSign.append("&CNYTYP=" + cnyTyp);
		
		//SIGN
		String sign = "";
		try {
			sign = ShanDongSignEnc.sign(mapToSign.toString());
		} catch (Exception e) {
			log.error(logPre + "加密发生异常"+e.getMessage(),e);
			return respResult;
		}
		request.append("<SIGN>").append(sign).append("</SIGN>");
		request.append("</MESSAGE>");
		String content = request.toString();
		String res = HttpRequestUtil.httpPost(URL, content);
		
		try {
			//响应报文验签
			Map<String,String> resMap = XmlMessgeUtil.xml2Map(res);
			String signStr = resMap.get("SIGNSTR");
			String signString = resMap.get("SIGN");
			try {
				if(!ShanDongSignEnc.verify(signStr, signString)){
					log.info(logPre + "验签失败" + res);
					return respResult;
				}
			} catch (SignEncException e) {
				log.error(logPre + "验签发生异常"+e.getMessage(),e);
				return respResult;
			}
			
			String rcode = resMap.get("RCODE");
			String desc = resMap.get("DESC");
			respResult.setRespCode(rcode);
			respResult.setRespMsg(desc);
		} catch (Exception e) {
			log.error(logPre + "xml2Map发生异常"+e.getMessage(),e);
		}
		return respResult;
	}
	
	/**
	 * 
	* @描述: wap在线支付
	* @创建人:cyb
	* @创建时间:2017年10月16日 下午4:29:50
	* @修改人：
	* @修改时间：
	* @修改描述
	* @param @param currency 币种 CNY：可提现金额进行支付；用户只能选择可体现账户里的钱和银行账户里的钱进行支付。
								 CMY：用不可提现金额支付，用户可以选择不可体现账户里面的钱+充值卡+银行卡进行支付
	* @param @param orderId 订单id 20位
	* @param @param price 金额 分为单位
	* @param @param orderLogTime 订单创建时间
	* @param @param goodsProductInfo 产品描述
	* @param @param goodsProductName 产品描述名称
	* @param @param batchId 产品编号（批次id）
	* @param @param mobile 手机号
	* @param @return
	* @return RespWap
	* @throws
	 */
	public static RespWap wap(String currency,String orderId,String price,Date orderLogTime,String goodsProductInfo,
			String goodsProductName,long batchId,String mobile){
		RespWap respResult = new RespWap();
		
		StringBuilder mapToSign = new StringBuilder();
		StringBuilder request = new StringBuilder();
		request.append("<MESSAGE>");
		String mcode = "101426";
		request.append("<MCODE>").append(mcode).append("</MCODE>");
		mapToSign.append("MCODE=" + mcode);
		
		Date currDate = new Date();
		String mid = FormatTime.toString(currDate, "yyyyMMddHHmmss");
		request.append("<MID>").append(mid).append("</MID>");
		mapToSign.append("&MID=" + mid);
		
		String date = DateUtil.toString(currDate, "yyyyMMdd");
		request.append("<DATE>").append(date).append("</DATE>");
		mapToSign.append("&DATE=" + date);
		
		String time = DateUtil.toString(currDate, "HHmmss");
		request.append("<TIME>").append(time).append("</TIME>");
		mapToSign.append("&TIME=" + time);
		
		request.append("<MERID>").append(MERID).append("</MERID>");
		mapToSign.append("&MERID=" + MERID);
		
		request.append("<ORDERID>").append(orderId).append("</ORDERID>");
		mapToSign.append("&ORDERID=" + orderId);
		
		request.append("<AMOUT>").append(price).append("</AMOUT>");
		mapToSign.append("&AMOUT=" + price);
		
		//是否允许用户对该笔订单进行评论 0表示允许，默认 1表示不允许
		request.append("<ALLOWNOTE>").append("0").append("</ALLOWNOTE>");
		mapToSign.append("&ALLOWNOTE=0");
		
		//推荐用户进行确认的方式
		request.append("<AUTHORIZEMODE>").append("WAP").append("</AUTHORIZEMODE>");
		mapToSign.append("&AUTHORIZEMODE=WAP");
		
		//币种 一般固定CNY（可提现金额）
		//CNY：可提现金额进行支付；用户只能选择可体现账户里的钱和银行账户里的钱进行支付。
		//CMY：用不可提现金额支付，用户可以选择不可体现账户里面的钱+充值卡+银行卡进行支付
		if(StringUtils.isBlank(currency)){
			request.append("<CURRENCY>").append("CNY").append("</CURRENCY>");
			mapToSign.append("&CURRENCY=CNY");
		}else{
			request.append("<CURRENCY>").append(currency).append("</CURRENCY>");
			mapToSign.append("&CURRENCY=" + currency);
		}
		
		String orderDate = DateUtil.toString(orderLogTime, "yyyyMMdd");
		request.append("<ORDERDATE>").append(orderDate).append("</ORDERDATE>");
		mapToSign.append("&ORDERDATE=" + orderDate);
		
		//PERIOD 有效期数值 半个小时内支付,超过则无法支付
		request.append("<PERIOD>").append("30").append("</PERIOD>");
		mapToSign.append("&PERIOD=30");
		
		//PERIODUNIT 有效期单位	1-月	2-日	3-小时	4-分钟
		request.append("<PERIODUNIT>").append("4").append("</PERIODUNIT>");
		mapToSign.append("&PERIODUNIT=4");
		
		//PRODUCTDESC 产品描述
		//String goodsProductInfo = orderInfo.getGoodsProductInfo();
		request.append("<PRODUCTDESC>").append(goodsProductInfo).append("</PRODUCTDESC>");
		mapToSign.append("&PRODUCTDESC=" + goodsProductInfo);
		
		//PRODUCTID	产品编号 批次id
		request.append("<PRODUCTID>").append(batchId).append("</PRODUCTID>");
		mapToSign.append("&PRODUCTID=" + batchId);
		
		//PRODUCTNAME 产品名称
		request.append("<PRODUCTNAME>").append(goodsProductName).append("</PRODUCTNAME>");
		mapToSign.append("&PRODUCTNAME=" + goodsProductName);
		
		//TXNTYP 交易类型 S：直接支付
		request.append("<TXNTYP>").append(TXNTYP_WAP).append("</TXNTYP>");
		mapToSign.append("&TXNTYP=" + TXNTYP_WAP);
		
		//CALLBACK 商户的响应URL，用户在手机支付平台页面支付后，重定向和通知的地址 页面同步返回
		request.append("<CALLBACK>").append(CALLBACK_URL).append("</CALLBACK>");
		mapToSign.append("&CALLBACK=" + CALLBACK_URL);
		
		//MOBILEID
		request.append("<MOBILEID>").append(mobile).append("</MOBILEID>");
		mapToSign.append("&MOBILEID=" + mobile);
		
		//SIGN
		String sign = "";
		try {
			sign = ShanDongSignEnc.sign(mapToSign.toString());
		} catch (Exception e) {
			log.error(logPre + "加密发生异常"+e.getMessage(),e);
			return respResult;
		}
		request.append("<SIGN>").append(sign).append("</SIGN>");
		request.append("</MESSAGE>");
		String content = request.toString();
		log.info(logPre + "wap请求参数:mobile=" + mobile + ",orderId=" + orderId);
		String res = HttpRequestUtil.httpPost(URL, content);
		//解析响应报文
		//响应报文验签
		try {
			Map<String,String> resMap = XmlMessgeUtil.xml2Map(res);
			String signStr = resMap.get("SIGNSTR");
			String signString = resMap.get("SIGN");
			try {
				if(!ShanDongSignEnc.verify(signStr, signString)){
					log.info(logPre + "验签失败" + res);
					return respResult;
				}
			} catch (Exception e) {
				log.error(logPre + "验签发生异常"+e.getMessage(),e);
				return respResult;
			}
			
			respResult.setRespCode(resMap.get("RCODE"));
			respResult.setRespMsg(resMap.get("DESC"));
			respResult.setToken(resMap.get("TOKEN"));
			log.info(logPre + "wap响应:respCode=" + respResult.getRespCode() + ",respMsg=" + respResult.getRespMsg());
		} catch (Exception e) {
			log.error(logPre + "xml2Map发生异常"+e.getMessage(),e);
		}
		return respResult;
	}
	
	public static String dealWithToken(String token){
		String[] temp1 = token.split("&lt;hi:\\$\\$&gt;");
		if(temp1 == null || temp1.length < TOKENARRLENGTH){
			return "";
		}
		
		try {
			String[] urlArr = temp1[0].split("&lt;hi:=&gt;");
			String url = urlArr[1];
			String method = temp1[1].split("&lt;hi:=&gt;")[1];
			String sessionId = temp1[2].split("&lt;hi:=&gt;")[1];
			return url + "?method=" + method + "&SESSIONID=" + sessionId;
		} catch (Exception e) {
			log.error(logPre + "token处理发生异常:"+e.getMessage(),e);
		}
		
		return "";
	}
	
}
